//
// Created by cjl on 2019-01-13.
//
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>

void adts_header(char *szAdtsHeader, int dataLen) {

    int audio_object_type = 2;
    int sampling_frequency_index = 7;
    int channel_config = 2;

    int adtsLen = dataLen + 7;

    szAdtsHeader[0] = 0xff;         //syncword:0xfff                          高8bits
    szAdtsHeader[1] = 0xf0;         //syncword:0xfff                          低4bits
    szAdtsHeader[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
    szAdtsHeader[1] |= (0 << 1);    //Layer:0                                 2bits
    szAdtsHeader[1] |= 1;           //protection absent:1                     1bit

    szAdtsHeader[2] =
            (audio_object_type - 1) << 6;            //profile:audio_object_type - 1                      2bits
    szAdtsHeader[2] |=
            (sampling_frequency_index & 0x0f) << 2; //sampling frequency index:sampling_frequency_index  4bits
    szAdtsHeader[2] |= (0 << 1);                             //private bit:0                                      1bit
    szAdtsHeader[2] |=
            (channel_config & 0x04) >> 2;           //channel configuration:channel_config               高1bit

    szAdtsHeader[3] = (channel_config & 0x03) << 6;     //channel configuration:channel_config      低2bits
    szAdtsHeader[3] |= (0 << 5);                      //original：0                               1bit
    szAdtsHeader[3] |= (0 << 4);                      //home：0                                   1bit
    szAdtsHeader[3] |= (0 << 3);                      //copyright id bit：0                       1bit
    szAdtsHeader[3] |= (0 << 2);                      //copyright id start：0                     1bit
    szAdtsHeader[3] |= ((adtsLen & 0x1800) >> 11);           //frame length：value   高2bits

    szAdtsHeader[4] = (uint8_t) ((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bits
    szAdtsHeader[5] = (uint8_t) ((adtsLen & 0x7) << 5);       //frame length:value    低3bits
    szAdtsHeader[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bits
    szAdtsHeader[6] = 0xfc;
}

void err_log(char *string, char *info) {
    av_log(NULL, AV_LOG_ERROR, "%s , info : %s\n", string, info);
}

int extra_audio() {
    int ret;
    char *srcPath = "/Users/caijinglong/code/c/demos/ffmpeg/log/src.mp4";
    char *outPath = "/Users/caijinglong/code/c/demos/ffmpeg/log/dst.aac";

    AVFormatContext *ctx = NULL;
//    AVOutputFormat *outputFormat = NULL;
//    AVStream *outStream = NULL;

    int audioIndex;

    FILE *outFile = fopen(outPath, "wb");

    if (!outFile) {
        err_log("can't open out file", "");
        return -1;
    }

    ret = avformat_open_input(&ctx, srcPath, NULL, NULL);
    if (ret < 0) {

        fclose(outFile);
        err_log("cannot open input src", av_err2str(ret));
        return ret;
    }

    av_dump_format(ctx, 0, srcPath, 0);
    printf("\n\n\n");

    ret = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (ret < 0) {

        avformat_close_input(&ctx);
        fclose(outFile);
        err_log("cannot find best stream", av_err2str(ret));
        return ret;
    }

    audioIndex = ret;

    AVPacket pkt;

    av_init_packet(&pkt);

    int len;

    while (av_read_frame(ctx, &pkt) >= 0) {
        if (pkt.stream_index == audioIndex) {
            char header_buf[7];
            adts_header(header_buf, pkt.size);
            fwrite(header_buf, 1, 7, outFile);

            len = fwrite(pkt.data, 1, (size_t) pkt.size, outFile);
            if (len != pkt.size) {
                av_log(NULL, AV_LOG_WARNING, "warning length of data is not equal size ok pkt \n");
            }
        }

        av_packet_unref(&pkt);
    }

    if (ctx) {
        avformat_close_input(&ctx);
    }
    fclose(outFile);

    return ret;
}

int extra_audio_use_api() {
    char *srcPath = "/Users/caijinglong/code/c/demos/ffmpeg/log/src.mp4";
    char *outPath = "/Users/caijinglong/code/c/demos/ffmpeg/log/dst_api.aac";
    AVFormatContext *pFormatCtx;
    AVOutputFormat *pFormat;
    AVCodec *codec;


    FILE *srcFile = fopen(srcPath, "rb");


    // 猜格式
    pFormatCtx = avformat_alloc_context();
    pFormat = av_guess_format(NULL, outPath, NULL);
    pFormatCtx->oformat = pFormat;

    if (avio_open(&pFormatCtx->pb, outPath, AVIO_FLAG_READ_WRITE) < 0) {
        printf("输出文件打开失败 \n");
        return -1;
    }

    avformat_new_stream(pFormatCtx, codec);

    return 0;
}

int main(int argc, char *args[]) {
    av_log_set_level(AV_LOG_DEBUG);

    printf("arg count = %d\n", argc);

    int ret;
    ret = extra_audio();
    if (ret < 0) {
        return ret;
    }

    return 0;
}

